// Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.

// aass客户端
package clients

import (
	"bytes"
	"codehub-g.huawei.com/videocloud/mediaprocesscenter/application-gateway/pkg/models/event"
	"encoding/json"
	"fmt"
	"net/http"
	"sync"

	"codehub-g.huawei.com/videocloud/mediaprocesscenter/application-gateway/config"
	"codehub-g.huawei.com/videocloud/mediaprocesscenter/application-gateway/pkg/apis"
	"codehub-g.huawei.com/videocloud/mediaprocesscenter/application-gateway/pkg/utils/hhmac"
	"codehub-g.huawei.com/videocloud/mediaprocesscenter/application-gateway/pkg/utils/log"
)

type aassClient struct {
	Cli      *Client
	AASSAddr string
}

// AASSClient client for aass
var AASSClient *aassClient

const getConfig = "v1/pod"

// InitAASSClient init aass client
func InitAASSClient() {
	var once sync.Once
	once.Do(func() {
		AASSClient = &aassClient{
			Cli:      NewHttpsClient(hhmac.LocalKeyAASS),
			AASSAddr: config.GlobalConfig.AassAddr,
		}
	})
}

// GetScalingGroupDetailsByFleetId 通过FleetId获取伸缩组基本信息
func (a *aassClient) GetScalingGroupDetailsByFleetId(fleetId string) (*apis.ScalingGroup, error) {
	req, err := NewRequest("GET", fmt.Sprintf("https://%s/v1/scaling-groups/%s/configuration", a.AASSAddr, fleetId), map[string][]string{}, nil)
	if err != nil {
		log.RunLogger.Errorf("[runtime configuration controller] failed to create a request for %v", err)
		return nil, fmt.Errorf("[aass client] failed to create a instance configuration request for %v", err)
	}
	statusCode, body, _, err := DoRequest(a.Cli, req)
	if err != nil {
		log.RunLogger.Errorf("[aass client] failed to get scaling group for fleet id %s, "+
			"error %v", fleetId, err)
		return nil, err
	}
	if statusCode != http.StatusOK {
		log.RunLogger.Errorf("[gateway client] failed to get scaling group for fleet id %s, "+
			"status code is %d", fleetId, statusCode)
		return nil, fmt.Errorf("expected status code %d, get status code %d", http.StatusOK, statusCode)
	}

	var sg apis.ScalingGroup
	err = json.Unmarshal(body, &sg)
	if err != nil {
		log.RunLogger.Errorf("[runtime configuration controller] failed to unmarshal request body for %v", err)
		return nil, fmt.Errorf("[aass client] failed to failed to unmarshal request body for %v", err)
	}

	log.RunLogger.Infof("[runtime configuration controller] get scaling group %+v", sg)

	return &sg, nil
}

// GetInstanceConfiguration get instance configuration
func (a *aassClient) GetInstanceConfiguration(sgID string) (*apis.InstanceConfiguration, error) {
	req, err := NewRequest("GET", fmt.Sprintf("https://%s/v1/instance-scaling-groups/%s/instance-configuration", a.AASSAddr, sgID), map[string][]string{}, nil)
	if err != nil {
		log.RunLogger.Errorf("[runtime configuration controller] failed to create a request for %v", err)
		return nil, fmt.Errorf("[aass client] failed to create a instance configuration request for %v", err)
	}

	statusCode, body, _, err := DoRequest(a.Cli, req)
	if err != nil {
		log.RunLogger.Errorf("[aass client] failed to get instance configuration for id %s, "+
			"error %v", sgID, err)
		return nil, err
	}
	if statusCode != http.StatusOK {
		log.RunLogger.Errorf("[gateway client] failed to get instance configuration for id %s, "+
			"status code is %d", sgID, statusCode)
		return nil, fmt.Errorf("expected status code %d, get status code %d", http.StatusOK, statusCode)
	}

	var itc apis.InstanceConfiguration
	err = json.Unmarshal(body, &itc)
	if err != nil {
		log.RunLogger.Errorf("[runtime configuration controller] failed to unmarshal request body for %v", err)
		return nil, fmt.Errorf("[aass client] failed to failed to unmarshal request body for %v", err)
	}

	log.RunLogger.Infof("[runtime configuration controller] get instance configuration %+v", itc)

	return &itc, nil
}

// RegisterEvent 上报Event给AASS
func (a *aassClient) RegisterEvent(registerReq *event.RegisterEventRequest, projectId string) {
	log.RunLogger.Infof("[register event] receive an event register request %s", registerReq.Name)
	body, err := json.Marshal(registerReq)
	if err != nil {
		log.RunLogger.Errorf("[register event] marshal req %+v err %+v", registerReq, err)
		return
	}
	req, err := NewRequest("POST", fmt.Sprintf("https://%s/v1/%s/event", a.AASSAddr, projectId), map[string][]string{}, bytes.NewReader(body))
	if err != nil {
		log.RunLogger.Errorf("[register event] register event %s err %+v", registerReq.Name, err)
		return
	}
	statusCode, body, _, err := DoRequest(a.Cli, req)
	if statusCode != http.StatusOK {
		log.RunLogger.Errorf("[gateway client] failed to get register an event %s "+
			"status code is %d for %v", registerReq.Name, statusCode, body)
		return
	}
	log.RunLogger.Infof("[register event] success to register an event %s", registerReq.Name)
}

// 通过hostname获取fleetid,sgid,instanceid,publicip,privateip,projectid
func (a *aassClient) GetConfigByHostname(hostname string) (*apis.GetConfig, error) {
	req, err := NewRequest("GET", fmt.Sprintf("https://%s/%s/%s", a.AASSAddr, getConfig, hostname), map[string][]string{}, nil)
	if err != nil {
		log.RunLogger.Errorf("[runtime get controller] failed to create a request for %v", err)
		return nil, fmt.Errorf("[aass client] failed to create a get config by hostname request for %v", err)
	}
	statusCode, body, _, err := DoRequest(a.Cli, req)
	if err != nil {
		log.RunLogger.Errorf("[aass client] failed to get config by hostname %s, "+
			"error %v", hostname, err)
		return nil, err
	}
	if statusCode != http.StatusOK {
		log.RunLogger.Errorf("[gateway client] failed to get config for hostname %s, "+
			"status code is %d", hostname, statusCode)
		return nil, fmt.Errorf("expected status code %d, get status code %d", http.StatusOK, statusCode)
	}

	var res apis.GetConfig
	err = json.Unmarshal(body, &res)
	if err != nil {
		log.RunLogger.Errorf("[runtime configuration controller] failed to unmarshal request body for %v", err)
		return nil, fmt.Errorf("[aass client] failed to failed to unmarshal request body for %v", err)
	}

	log.RunLogger.Infof("[runtime configuration controller] get config %+v", res)

	return &res, nil
}
